package com.zh.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zh.common.BaseResponse;
import com.zh.common.DeleteRequest;
import com.zh.common.ErrorCode;
import com.zh.common.ResultUtils;
import com.zh.constant.UserConstant;
import com.zh.domain.Model.IpDto;
import com.zh.domain.dto.user.*;
import com.zh.domain.entity.LoginLog;
import com.zh.domain.entity.User;
import com.zh.domain.vo.user.UserVO;
import com.zh.exception.BusinessException;
import com.zh.exception.ThrowUtils;
import com.zh.manager.ThreadManager;
import com.zh.service.LoginLogService;
import com.zh.service.UserService;
import com.zh.utils.IpUtils;
import com.zh.utils.RSAUtil;
import eu.bitwalker.useragentutils.UserAgent;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;

/**
 * 用户接口
 */
@RestController
@RequestMapping("/user")
@Slf4j
@Api(tags = "UserController", value = "用户控制器")
public class UserController {

    @Resource
    private UserService userService;
    @Resource
    private LoginLogService loginLogService;

    /**
     * 用户注册
     *
     * @param userRegisterRequest 用户注册请求
     * @return 用户id
     */
    @PostMapping("/register")
    @ApiOperation("用户注册")
    public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
        //1.参数获取
        String username = userRegisterRequest.getUsername();
        String passwordStr = userRegisterRequest.getPassword();
        String rePasswordStr = userRegisterRequest.getRePassword();
        String nickname = userRegisterRequest.getNickname();
        String name = userRegisterRequest.getName();
        //2.密码解密
        String privateKey = RSAUtil.getPrivateKey();
        String password = RSAUtil.decryptByPrivateKey(passwordStr, privateKey);
        String rePassword = RSAUtil.decryptByPrivateKey(rePasswordStr, privateKey);
        //3.调用注册
        long result = userService.userRegister(username, password, rePassword, nickname, name);
        //4.返回注册成功用户id
        return ResultUtils.success(result);
    }

    /**
     * 用户登录
     *
     * @param userLoginRequest 用户登录请求
     * @param response         响应
     * @param request          请求
     * @return 用户视图
     */
    @PostMapping("/login")
    @ApiOperation(value = "用户登录")
    public BaseResponse<UserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request, HttpServletResponse response) {
        //1.参数获取
        String username = userLoginRequest.getUsername();
        String passwordStr = userLoginRequest.getPassword();
        //2.密码解密
        String privateKey = RSAUtil.getPrivateKey();
        String password = RSAUtil.decryptByPrivateKey(passwordStr, privateKey);
        //3.调用登录
        UserVO loginUserVO = userService.userLogin(username, password, request, response);
        //4.保存登录日志
        IpDto ipDto = IpUtils.getIpAddress(request);
        ThreadManager.execute(() -> {
            try {
                LoginLog loginLog = new LoginLog();
                UserAgent userAgent = IpUtils.getUserAgent(request);
                loginLog.setLoginId(loginUserVO.getId());
                String device = userAgent.getOperatingSystem().getName()
                        +" "
                        +userAgent.getBrowser().getName();
                loginLog.setDevice(device);
                loginLog.setAddress(ipDto.getRealRegion() + " " + ipDto.getIp());
                loginLog.setLoginTime(LocalDateTime.now());
                loginLogService.save(loginLog);
            } catch (Exception e) {
                log.error("保存登录日志失败-id:{} ", loginUserVO.getId(), e);
            }
        });
        return ResultUtils.success(loginUserVO);
    }

    /**
     * 退出登录
     */
    @SaCheckLogin
    @PostMapping("/logout")
    @ApiOperation("退出登录")
    @ApiImplicitParams(@ApiImplicitParam(name = "Authorization", value = "token", required = true, paramType = "header", dataType = "string"))
    public BaseResponse<Boolean> userLogout(HttpServletResponse response) {
        ThrowUtils.throwIf(!StpUtil.isLogin(), ErrorCode.NO_AUTH_ERROR, "未登录", e -> response.setStatus(401));
        StpUtil.logout();
        return ResultUtils.success(true);
    }

    /**
     * 获取当前登录用户
     *
     * @return
     */
    @GetMapping("/online")
    @ApiOperation(value = "获取当前登录用户")
    @SaCheckLogin
    @ApiImplicitParams(@ApiImplicitParam(name = "Authorization", value = "token", required = true, paramType = "header", dataType = "string"))
    public BaseResponse<UserVO> getLoginUser() {
        int userId = StpUtil.getLoginIdAsInt();
        UserVO userVO = userService.getUserVoById(userId);
        return ResultUtils.success(userVO);
    }


    // region 增删改查

    /**
     * 创建用户 超管/管理员可进入
     *
     * @param userAddRequest
     * @return
     */
    @PostMapping("/add")
    @SaCheckLogin
    @SaCheckRole(value = {UserConstant.ADMIN, UserConstant.SUPER_ADMIN}, mode = SaMode.OR)
    @ApiImplicitParams(@ApiImplicitParam(name = "Authorization", value = "token", required = true, paramType = "header", dataType = "string"))
    @ApiOperation(value = "创建用户,超管/管理员可进入")
    public BaseResponse<Integer> addUser(@RequestBody UserAddRequest userAddRequest, HttpServletResponse response) {
        //1.参数校验
        if (userAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Integer id = userService.add(userAddRequest, response);
        return ResultUtils.success(id);
    }

    /**
     * 删除用户 超管/管理员可进入
     *
     * @param deleteRequest
     * @param response
     * @return
     */
    @SaCheckLogin
    @SaCheckRole(value = {UserConstant.ADMIN, UserConstant.SUPER_ADMIN}, mode = SaMode.OR)
    @DeleteMapping("/delete")
    @ApiImplicitParams(@ApiImplicitParam(name = "Authorization", value = "token", required = true, paramType = "header", dataType = "string"))
    @ApiOperation(value = "删除用户,超管/管理员可进入")
    public BaseResponse<Boolean> deleteUser(@RequestBody DeleteRequest deleteRequest, HttpServletResponse response) {
        //1.参数校验
        ThrowUtils.throwIf(deleteRequest == null || deleteRequest.getId() <= 0, ErrorCode.PARAMS_ERROR);
        boolean success = userService.removeUserById(deleteRequest, response);
        return ResultUtils.success(success);
    }

    /**
     * 更新用户
     *
     * @param userUpdateRequest
     * @return
     */
    @PutMapping("/update")
    @ApiOperation(value = "更新用户,更新密码时密踢出,可自己更新自己,管理员也可更新,但只能更新自己创建的")
    @SaCheckLogin
    @ApiImplicitParams(@ApiImplicitParam(name = "Authorization", value = "token", required = true, paramType = "header", dataType = "string"))
    public BaseResponse<Boolean> updateUser(@RequestBody UserUpdateRequest userUpdateRequest) {
        //1.参数校验
        ThrowUtils.throwIf(userUpdateRequest == null || userUpdateRequest.getId() == null, ErrorCode.PARAMS_ERROR);
        //2.参数提取
        String privateKey = RSAUtil.getPrivateKey();
        String passwordStr = userUpdateRequest.getPassword();
        String rePasswordStr = userUpdateRequest.getRePassword();
        String password = RSAUtil.decryptByPrivateKey(passwordStr, privateKey);
        String rePassword = RSAUtil.decryptByPrivateKey(rePasswordStr, privateKey);
        userUpdateRequest.setPassword(password);
        userUpdateRequest.setRePassword(rePassword);
        //3.服务调用
        boolean result = userService.updateUser(userUpdateRequest);
        return ResultUtils.success(result);
    }

    /**
     * 根据 id 获取用户视图
     *
     * @param id
     * @return
     */
    @GetMapping("/get")
    @ApiOperation(value = "根据 id 获取用户视图")
    @ApiImplicitParams(@ApiImplicitParam(name = "Authorization", value = "token", required = true, paramType = "header", dataType = "string"))
    public BaseResponse<UserVO> getUserById(Integer id) {
        //1.参数校验
        ThrowUtils.throwIf(id == null || id <= 0, ErrorCode.PARAMS_ERROR);
        //2.调用服务
        UserVO userVO = userService.getUserVoById(id);
        return ResultUtils.success(userVO);
    }

    /**
     * 分页获取用户列表（仅管理员/超管）
     *
     * @param userQueryRequest
     * @return
     */
    @SaCheckLogin
    @SaCheckRole(value = {UserConstant.ADMIN, UserConstant.SUPER_ADMIN}, mode = SaMode.OR)
    @PostMapping("/list/page")
    @ApiOperation(value = "分页获取用户列表（仅管理员/超管）")
    @ApiImplicitParams(@ApiImplicitParam(name = "Authorization", value = "token", required = true, paramType = "header", dataType = "string"))
    public BaseResponse<IPage<User>> listUserByPage(@RequestBody UserQueryRequest userQueryRequest) {
        userQueryRequest.standardizeSize();
        long current = userQueryRequest.getCurrent();
        long size = userQueryRequest.getPageSize();
        IPage<User> userPage = userService.page(new Page<>(current, size),
                userService.getQueryWrapper(userQueryRequest));
        return ResultUtils.success(userPage);
    }
    // endregion
}
